/**
 * 维护用户“自建应用”
 */
import { getLogger, Service } from '@gnlab/utils'
import { MemSubject } from '@gnlab/utils/rx'
import config from '@/config'
import { safeJSONParse } from '@/lib/utils'
import { appendSDKQuery } from '@/sdk/host'
import type { Services } from '@/services'
import { API } from '@/services/common/api'

const logger = getLogger('services/features/third-apps')

export interface ThirdApp {
  id: number
  name: string
  icon: string
  url: string
  html: string // url 和 html 都存在的情况下，html 优先
}

/**
 * 历史原因，后端返回的 Url 有两种可能：
 * - 老格式，URL 字符串：http://baidu.com
 * - 新格式，JSON 字符串：{ url: string, html: string }
 */
interface RespThirdApp {
  Id: number
  Name: string
  Url: string
  Icon: string
}

export class ThirdApps extends Service<Services> {
  private get auth() {
    return this.services.auth
  }

  list = new MemSubject<ThirdApp[]>([])

  registered() {
    void Promise.resolve(this.auth.accountId).then(() => void this.load())
  }

  async load() {
    const res = await API<RespThirdApp[]>('/Config/GetApps')
    if (res.success) {
      const list = res.data.map(raw => {
        let url = ''
        let html = ''
        const json = safeJSONParse<{ url: string; html: string }>(raw.Url)
        if (json && 'url' in json && 'html' in json) {
          url = json.url!
          html = json.html!
        } else {
          url = raw.Url
        }
        return {
          id: raw.Id,
          name: raw.Name,
          icon: raw.Icon,
          url,
          html,
        }
      })
      this.list.next(list)
    } else {
      logger.warn('应用列表加载失败', res.error)
    }
  }

  async addOrUpdate(data: Omit<ThirdApp, 'id'> & { id?: number }) {
    const res = await API('/Config/SaveApp', {
      data: {
        Id: data.id,
        Name: data.name,
        Url: JSON.stringify({ url: data.url, html: data.html }),
        Icon: data.icon,
      },
    })
    void this.load()
    if (res.success) {
      return true
    } else {
      logger.warn(`应用保存失败：${res.error}`)
      return res.error
    }
  }

  async remove(id: number) {
    const res = await API('/Config/RemoveApp', { data: { Id: id } })
    void this.load()
    if (res.success) {
      return true
    } else {
      logger.warn(`应用删除失败：${res.error}`)
      return res.error
    }
  }

  openByURL(id: number) {
    const app = this.list.value.find(v => v.id === id)
    if (!app) {
      logger.warn(`找不到应用，打开失败，id：${id}`)
      return
    }

    this.services.sdkHost.touchInstance()
    const { url } = app
    const width = Math.round(screen.width * 0.5)
    const height = Math.round(screen.height * 0.5)
    window.open(
      appendSDKQuery(url),
      '_blank',
      `toolbar,scrollbars,resizable,top=500,left=500,width=${width},height=${height}`,
    )
  }

  // 方法来自：https://stackoverflow.com/a/60888041/2815178
  openByHTML(id: number, iframe: HTMLIFrameElement) {
    const app = this.list.value.find(v => v.id === id)
    if (!app) {
      logger.warn(`找不到应用，打开失败，id：${id}`)
      return
    }

    this.services.sdkHost.touchInstance()

    let html = app.html
    const envScript = '\n<script>window.inQunTool = 1</script>\n'

    const clientFilename = 'quntool-jssdk-1.1.0.js'
    let currentPath = location.href.replace('index.html', '')
    if (!currentPath.endsWith('/')) currentPath += '/'
    const clientScript = `<script src="${currentPath + clientFilename}"></script>\n`

    const firstScriptIndex = html.indexOf('<script')
    if (firstScriptIndex > -1) {
      html = [
        html.slice(0, firstScriptIndex),
        envScript,
        clientScript,
        html.slice(firstScriptIndex),
      ].join('\n')
    } else {
      html += envScript + clientScript + '\n'
    }

    /*
    开发模式下，JSSDK 必须以 ES6 Module 的形式载入，否则代码会报错。
    （因为 Vite 建议开启 TypeScript 的 isolatedModules 开关，此开关又会强制在代码里添加一个 export）
    又因此，其他脚本也必须以 ES6 Module 的形式载入，否则载入顺序会比 JSSDK 早。
    所以这里给所有 <script> 标签添加 module 标识。
    */
    if (config.IN_DEVELOPMENT) {
      html = html.replace(/<script/g, '<script type="module"')
    }

    iframe.srcdoc = html
  }
}

// 示例 HTML 应用
/*
<button>显示企微列表</button>

<script>
async function showQywxs() {
  const result = await window.QunTool.invoke('get-qywx-list')
  if (result.success) {
    const txt = result.data.map(qywx => `${qywx.username}-${qywx.wxid}`).join('\n')
    alert(txt)
  } else {
    alert('执行失败')
  }
}

document.querySelector('button')
  .addEventListener('click', showQywxs)
</script>
*/
